﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Resto.CostControl.Core.Domain.Model;
using Resto.CostControl.Core.Enums;
using Enterprise.Framework.Core.Exceptions;
using Resto.CostControl.Core.Domain.Query.MaterialModule;
using Enterprise.Framework.Core.Container;
using Resto.CostControl.Core.Cache;
using Resto.CostControl.Common.Consts;
using System.ComponentModel.DataAnnotations;

namespace Resto.CostControl.Core.Facade.MaterialModule.DataTransferObject
{
    /// <summary>
    /// 品名的DTO类
    /// </summary>
    [Serializable]
    public class MaterialDTO
    {
        #region 构造函数

        public MaterialDTO() { }

        internal MaterialDTO(Material material)
        {
            this.ID = material.ID;
            this.CurrentPrice = material.CurrentPrice;
            this.ActualSorage = material.ActualStorage;
            this.Type = (MaterialType)Enum.Parse(typeof(MaterialType), material.Type);

            this.Code = material.Code;
            this.Name = material.Name;
            this.SafeStorage = material.SafeStorage;
            this.Specification = material.Specification;
            this.Unit = material.Unit;
            this.CategoryCode = material.Category;
            this.Remark = material.Remark;

            if (material is SemiMaterial)
            {
                SemiMaterial semiMaterial = material as SemiMaterial;

                this.ProcessRate = semiMaterial.ProcessRate;
                this.RawMaterialId = semiMaterial.RawMaterialID;
            }
        }

        #endregion

        #region 基本属性

        public string ID { get; set; }

        /// <summary>
        /// 编号
        /// </summary>
        [Display(Name = "品名编号")]
        public string Code { get; set; }

        /// <summary>
        /// 名称
        /// </summary>
        [Display(Name = "品名名称")]
        public string Name { get; set; }

        /// <summary>
        /// 单位（公斤等）
        /// </summary>
        [Display(Name = "品名单位")]
        public string Unit { get; set; }

        /// <summary>
        /// 规格
        /// </summary>
        [Display(Name = "品名规格")]
        public string Specification { get; set; }

        /// <summary>
        /// 当前价格(新增时，原材料的价格是输入的，半成品的价格由系统自动计算出)
        /// </summary>
        /// <remarks>
        /// 只有新增时可以赋值
        /// </remarks>
        [Display(Name = "市场价格")]
        public decimal CurrentPrice { get; set; }

        /// <summary>
        /// 安全库存数
        /// </summary>
        [Display(Name = "安全库存")]
        public decimal SafeStorage { get; set; }

        /// <summary>
        /// 实际库存
        /// </summary>
        [Display(Name = "实际库存")]
        public decimal ActualSorage { get; set; }

        /// <summary>
        /// 品名类别：是原材料，还是半成品
        /// </summary>
        [Display(Name = "品名类别")]
        public MaterialType Type { get; set; }

        /// <summary>
        /// 品名大类代码
        /// </summary>
        [Display(Name = "品名大类")]
        public string CategoryCode { get; set; }

        /// <summary>
        /// 品名大类名称
        /// </summary>
        [Display(Name = "品名大类名称")]
        public string CategoryName
        {
            get
            {
                return DictionaryVOArrayCache.GetDicNameByCode(DictionaryTypeConsts.String_MaterialCategory_Code, CategoryCode);
            }
        }

        /// <summary>
        /// 备注
        /// </summary>
        [Display(Name = "备注")]
        public string Remark { get; set; }
        #endregion

        #region 私有属性

        [NonSerialized]
        private MaterialDTO _RawMaterial;
        private MaterialDTO RawMaterial
        {
            get
            {
                if (_RawMaterial == null && !string.IsNullOrWhiteSpace(this.RawMaterialId))
                    _RawMaterial = MaterialDTOCache.Get(this.RawMaterialId);

                return _RawMaterial;
            }
        }

        #endregion

        #region 半成品独有的属性

        /// <summary>
        /// 半成品所对应的原材料Id
        /// </summary>
        [Display(Name = "所属原材料")]
        public string RawMaterialId { get; set; }

        /// <summary>
        /// 半成品所对应的原材料名称
        /// </summary>
        [Display(Name = "所属原材料名称")]
        public string RawMaterialName
        {
            get
            {
                if (RawMaterial != null)
                    return RawMaterial.Name;
                else
                    return string.Empty;
            }
        }

        /// <summary>
        /// 半成品所对应的原材料价格
        /// </summary>
        [Display(Name = "所属原材料的市场价格")]
        public decimal RawMaterialPrice
        {
            get
            {
                if (RawMaterial != null)
                    return RawMaterial.CurrentPrice;
                else
                    return 0m;
            }
        }

        /// <summary>
        /// 加工率，
        /// 加工率 = 切后重量 / 切前重量 
        /// </summary>
        [Display(Name = "加工率")]
        public decimal ProcessRate { get; set; }

        #endregion

        #region 方法

        public bool IsRawMaterial()
        {
            return this.Type == MaterialType.RawMaterial;
        }

        public bool IsSemiMaterial()
        {
            return this.Type == MaterialType.SemiMaterial;
        }

        internal Material ToMaterial()
        {
            Material material;
            if (IsRawMaterial())
                material = new RawMaterial();
            else if (IsSemiMaterial())
                material = new SemiMaterial();
            else
            {
                string msg = "{0}类型的品名不存在";
                throw new BusinessException(string.Format(msg, this.Type));
            }

            //这3个属性只能在新增时赋值
            material.CurrentPrice = this.CurrentPrice;
            material.ActualStorage = this.ActualSorage;
            material.Type = this.Type.ToString();
            material.Remark = this.Remark;

            CopyToMaterial(material);

            return material;
        }


        internal void CopyToMaterial(Material material)
        {
            material.Code = this.Code;
            material.Name = this.Name;
            material.SafeStorage = this.SafeStorage;
            material.Specification = this.Specification;
            material.Unit = this.Unit;
            material.Category = this.CategoryCode;
            material.Remark = this.Remark;

            if (material is SemiMaterial)
                CopyToSemiMaterial(material as SemiMaterial);
        }

        private void CopyToSemiMaterial(SemiMaterial material)
        {
            material.ProcessRate = this.ProcessRate;
            material.RawMaterialID = this.RawMaterialId;
        }

        #endregion
    }
}
